package net.unit8.occupypub.cert; import net.unit8.occupypub.model.Cert; import net.unit8.occupypub.model.User; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameBuilder; import org.bouncycastle.asn1.x500.style.BCStyle; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.crypto.engines.DESedeEngine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.pkcs.*; import org.bouncycastle.pkcs.bc.BcPKCS12MacCalculatorBuilder; import org.bouncycastle.pkcs.bc.BcPKCS12PBEOutputEncryptorBuilder; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; import org.bouncycastle.pkcs.jcajce.JcaPKCS12SafeBagBuilder; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; import org.bouncycastle.util.io.pem.PemWriter; import java.io.FileWriter; import java.io.IOException; import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; /** * @author kawasima */ public class CertificationAuthority { static { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); } private Path pemPath; private Path keyPath; public CertificationAuthority() { } public CertificationAuthority(Path pemPath, Path keyPath) { this.pemPath = pemPath; this.keyPath = keyPath; } public KeyPair generateKey() throws NoSuchProviderException, NoSuchAlgorithmException { KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); return kpGen.generateKeyPair(); } public PKCS10CertificationRequest generateCSR(User user, KeyPair key) throws OperatorCreationException { X500Name x500User = new X500NameBuilder() .addRDN(BCStyle.C, user.getCountryName()) .addRDN(BCStyle.ST, user.getProvinceName()) .addRDN(BCStyle.L, user.getLocalityName()) .addRDN(BCStyle.O, user.getOrganizationName()) .addRDN(BCStyle.OU, user.getOrganizationUnitName()) .addRDN(BCStyle.CN, user.getCommonName()) .addRDN(BCStyle.EmailAddress, user.getEmailAddress()) .build(); PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder( x500User, key.getPublic()); user.setPrivateKey(key.getPrivate().getEncoded()); JcaContentSignerBuilder csBuilder= new JcaContentSignerBuilder("SHA512WithRSAEncryption"); ContentSigner signer = csBuilder.build(key.getPrivate()); return p10Builder.build(signer); } protected void generateCA() throws NoSuchProviderException, NoSuchAlgorithmException, IOException, OperatorCreationException { KeyPair pair = generateKey(); LocalDateTime startDate = LocalDate.now().atStartOfDay(); X509v3CertificateBuilder builder= new X509v3CertificateBuilder( new X500Name("CN=ca"), new BigInteger("0"), Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()), Date.from(startDate.plusDays(3650).atZone(ZoneId.systemDefault()).toInstant()), new X500Name("CN=ca"), SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded())); JcaContentSignerBuilder csBuilder= new JcaContentSignerBuilder("SHA512WithRSAEncryption"); ContentSigner signer = csBuilder.build(pair.getPrivate()); X509CertificateHolder holder = builder.build(signer); try (PemWriter writer = new PemWriter(new FileWriter(pemPath.toFile()))) { writer.writeObject(new PemObject("CERTIFICATE", holder.toASN1Structure().getEncoded())); } try (PemWriter writer = new PemWriter(new FileWriter(keyPath.toFile()))) { writer.writeObject(new PemObject("PRIVATE KEY", pair.getPrivate().getEncoded())); } } protected X509CertificateHolder readCertificate() throws IOException, CertificateException { try (PemReader reader = new PemReader(Files.newBufferedReader(pemPath))) { PemObject pem = reader.readPemObject(); return new X509CertificateHolder(pem.getContent()); } } protected AsymmetricKeyParameter readKey(Path keyPath) throws IOException { try (PemReader reader = new PemReader(Files.newBufferedReader(keyPath))) { PemObject pem = reader.readPemObject(); return PrivateKeyFactory.createKey(pem.getContent()); } } public X509Certificate generateCertificate(PKCS10CertificationRequest csr, BigInteger serial, int expireDays) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, OperatorCreationException, CertificateException { AlgorithmIdentifier sigAlgorithmId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA512WithRSAEncryption"); AlgorithmIdentifier digestAlgorithmId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgorithmId); X509CertificateHolder caCert = readCertificate(); System.out.println(caCert.getSubject()); LocalDateTime startDate = LocalDate.now().atStartOfDay(); X509v3CertificateBuilder builder= new X509v3CertificateBuilder( caCert.getSubject(), serial, Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()), Date.from(startDate.plusDays(expireDays).atZone(ZoneId.systemDefault()).toInstant()), csr.getSubject(), SubjectPublicKeyInfo.getInstance(csr.getSubjectPublicKeyInfo())); AsymmetricKeyParameter caPrivateKeyParameters = readKey(keyPath); ContentSigner contentSigner = new BcRSAContentSignerBuilder(sigAlgorithmId, digestAlgorithmId) .build(caPrivateKeyParameters); X509CertificateHolder holder = builder.build(contentSigner); return new JcaX509CertificateConverter().setProvider("BC").getCertificate(holder); } public PKCS12PfxPdu generatePKCS12(X509Certificate caCert, Cert clientCert, String password) throws IOException, CertificateException, PKCSException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException { PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(caCert); X509CertificateHolder clientCertHolder =new X509CertificateHolder(clientCert.getClientCert()); PKCS12SafeBagBuilder clientCertBagBuilder = new JcaPKCS12SafeBagBuilder(new JcaX509CertificateConverter().setProvider("BC").getCertificate(clientCertHolder)); PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder( KeyFactory.getInstance("RSA", "BC").generatePrivate(new PKCS8EncodedKeySpec(clientCert.getPrivateKey())), new BcPKCS12PBEOutputEncryptorBuilder( PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher((new DESedeEngine()))).build(password.toCharArray())); PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); PKCS12SafeBag[] certs = new PKCS12SafeBag[2]; certs[0] = clientCertBagBuilder.build(); certs[1] = caCertBagBuilder.build(); pfxPduBuilder.addData(keyBagBuilder.build()); return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), password.toCharArray()); } }